package edu.stanford.bmir.protege.web.client.ui.ontology.stkos.common.treepanel;

import java.util.List;

import com.google.gwt.core.shared.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.web.bindery.event.shared.Event.Type;
import com.gwtext.client.widgets.tree.TreeNode;

import edu.stanford.bmir.protege.web.client.project.Project;
import edu.stanford.bmir.protege.web.client.rpc.OntologyServiceManager;
import edu.stanford.bmir.protege.web.client.rpc.data.EntityData;
import edu.stanford.bmir.protege.web.client.rpc.data.PropertyEntityData;
import edu.stanford.bmir.protege.web.client.rpc.data.PropertyType;
import edu.stanford.bmir.protege.web.shared.event.AnnotationPropertyFrameChangedEvent;
import edu.stanford.bmir.protege.web.shared.event.AnnotationPropertyFrameChangedEventHandler;
import edu.stanford.bmir.protege.web.shared.event.DataPropertyFrameChangedEvent;
import edu.stanford.bmir.protege.web.shared.event.DataPropertyFrameChangedEventHandler;
import edu.stanford.bmir.protege.web.shared.event.ObjectPropertyFrameChangedEvent;
import edu.stanford.bmir.protege.web.shared.event.ObjectPropertyFrameChangedEventHandler;
import edu.stanford.bmir.protege.web.shared.project.ProjectId;

/**
 * Stkos Property Tree Panel
 * 
 * @author LWS
 * 
 */
@SuppressWarnings("unchecked")
public class StkosPropertyTreePanel extends AbstractStkosTreePanel {

	public StkosPropertyTreePanel(Project project) {
		super(project);
	}

	@Override
	protected void registerProjectEventHandler() {
	}
	
	protected void registerProjectEventHandler2222() {
		if (getProject() == null || getProject().getProjectId() == null) {
			return;
		}

		ProjectId projectId = getProject().getProjectId();

		// Annotation Changed Event Handler

		Type<AnnotationPropertyFrameChangedEventHandler> type = AnnotationPropertyFrameChangedEvent.TYPE;

		AnnotationPropertyFrameChangedEventHandler handler = new AnnotationPropertyFrameChangedEventHandler() {
			@Override
			public void annotationPropertyFrameChanged(
					AnnotationPropertyFrameChangedEvent event) {
				if (event == null || event.getEntity() == null
						|| event.getEntity().getIRI() == null) {
					return;
				}
				try {
					TreeNode node = (TreeNode) getNodeById(event.getEntity()
							.getIRI().toString());

					refreshTreeNode(node);
				} catch (Exception e) {
					GWT.log("Update tree node text error.", e);
				}
			}
		};

		AbstractStkosTreePanel.manager.registerHandlerToProject(projectId,
				type, handler);

		// Datatype Changed Event Handler

		Type<DataPropertyFrameChangedEventHandler> type2 = DataPropertyFrameChangedEvent.TYPE;

		DataPropertyFrameChangedEventHandler handler2 = new DataPropertyFrameChangedEventHandler() {
			private static final long serialVersionUID = 1L;

			@Override
			public void dataPropertyFrameChanged(
					DataPropertyFrameChangedEvent event) {
				if (event == null || event.getEntity() == null
						|| event.getEntity().getIRI() == null) {
					return;
				}
				try {
					TreeNode node = (TreeNode) getNodeById(event.getEntity()
							.getIRI().toString());

					refreshTreeNode(node);
				} catch (Exception e) {
					GWT.log("Update tree node text error.", e);
				}
			}
		};

		AbstractStkosTreePanel.manager.registerHandlerToProject(projectId,
				type2, handler2);

		// Object Changed Event Handler

		Type<ObjectPropertyFrameChangedEventHandler> type3 = ObjectPropertyFrameChangedEvent.TYPE;

		ObjectPropertyFrameChangedEventHandler handler3 = new ObjectPropertyFrameChangedEventHandler() {
			@Override
			public void objectPropertyFrameChanged(
					ObjectPropertyFrameChangedEvent event) {
				if (event == null || event.getEntity() == null
						|| event.getEntity().getIRI() == null) {
					return;
				}
				try {
					TreeNode node = (TreeNode) getNodeById(event.getEntity()
							.getIRI().toString());

					refreshTreeNode(node);
				} catch (Exception e) {
					GWT.log("Update tree node text error.", e);
				}
			}
		};

		AbstractStkosTreePanel.manager.registerHandlerToProject(projectId,
				type3, handler3);

	}

	@Override
	protected void setRootNodeChild() {
		if (getProject() == null || getProject().getProjectId() == null) {
			return;
		}
		OntologyServiceManager.getInstance().getSubproperties(
				getProject().getProjectId(), null,
				new AsyncCallback<List<EntityData>>() {

					@Override
					public void onFailure(Throwable caught) {
						createClassRootNodeChild(null);
					}

					@Override
					public void onSuccess(final List<EntityData> result) {
						createClassRootNodeChild(result);
					}
				});
	}

	private void createClassRootNodeChild(List<EntityData> entityDatas) {
		if (entityDatas == null || entityDatas.size() == 0) {
			TreeNode rootChildTreeNode = new TreeNode("Unknow");
			rootChildTreeNode.setLeaf(true);
			rootChildTreeNode.setExpandable(false);
			rootChildTreeNode.setTooltip("Root node is not defined");
			rootChildTreeNode.setIconCls("protege-slot-icon");

			getRootNode().appendChild(rootChildTreeNode);
			return;
		}

		System.out.println(entityDatas);
		
		AsyncCallback<EntityData> callback = new AsyncCallback<EntityData>() {

			@Override
			public void onFailure(Throwable caught) {
				GWT.log("Failure", caught);
			}

			@Override
			public void onSuccess(EntityData result) {
				TreeNode treeNode = createTreeNode(result);
				if (treeNode != null) {
					getRootNode().appendChild(treeNode);
				}
			}

		};

		for (EntityData entityData : entityDatas) {
			getEntityChildrenCount(entityData, callback);
		}
	}

	private void getEntityChildrenCount(final EntityData entityData,
			final AsyncCallback<EntityData> callback) {
		if (entityData == null) {
			if (callback != null) {
				callback.onFailure(new Throwable(
						"Entity is null!operation failure!"));
				callback.onSuccess(entityData);
			}
			return;
		}
		entityData.setProperty("childrenCount", "0");
		if (getProject() == null || getProject().getProjectId() == null) {
			if (callback != null) {
				callback.onSuccess(entityData);
			}
			return;
		}
		OntologyServiceManager.getInstance().getSubproperties(
				getProject().getProjectId(), entityData.getName(),
				new AsyncCallback<List<EntityData>>() {

					@Override
					public void onFailure(Throwable caught) {
						if (callback != null) {
							callback.onFailure(caught);
							callback.onSuccess(entityData);
						}
					}

					@Override
					public void onSuccess(final List<EntityData> result) {
						if (result != null && result.size() > 0) {
							entityData.setProperty("childrenCount",
									result.size() + "");
						}
						if (callback != null) {
							callback.onSuccess(entityData);
						}
					}
				});
	}

	@Override
	protected TreeNode createTreeNode(EntityData entityData) {
		TreeNode node = super.createTreeNode(entityData);

		if (node == null) {
			return node;
		}

		updateNodeIconCls(node, entityData);

		updateNodeText(node, entityData);

		int childrenCount = 0;
		try {
			childrenCount = Integer.parseInt(entityData
					.getProperty("childrenCount"));
		} catch (Exception e) {
		}

		if (childrenCount > 0) {
			node.setLeaf(false);
			node.setExpandable(true);
		}

		return node;
	}

	private void updateNodeIconCls(TreeNode node, EntityData entityData) {
		if (node == null) {
			return;
		}
		String iconCls = "protege-slot-icon";
		if (entityData != null && entityData instanceof PropertyEntityData) {
			PropertyType type = ((PropertyEntityData) entityData)
					.getPropertyType();
			if (type == PropertyType.OBJECT) {
				iconCls = "protege-object-property-icon";
			} else if (type == PropertyType.DATATYPE) {
				iconCls = "protege-datatype-property-icon";
			} else if (type == PropertyType.ANNOTATION) {
				iconCls = "protege-annotation-property-icon";
			}
		}
		node.setIconCls(iconCls);
	}

	private void updateNodeText(TreeNode node, EntityData entityData) {
		if (node == null || entityData == null) {
			return;
		}
		String text = "";
		int localAnnotationsCount = entityData.getLocalAnnotationsCount();
		if (localAnnotationsCount > 0) {
			text = "<img src=\"images/comment-small-filled.png\" />" + " "
					+ localAnnotationsCount;
		}
		int childrenAnnotationsCount = entityData.getChildrenAnnotationsCount();
		if (childrenAnnotationsCount > 0) {
			text = text + " chd: " + childrenAnnotationsCount;
		}
		text = text + node.getText();
		node.setText(text);
	}

	@Override
	protected void getChildren(final TreeNode node) {
		if (node == null || node.getId() == null) {
			return;
		}
		if (node.getChildNodes() != null && node.getChildNodes().length > 0) {
			return;
		}
		if (ROOTNODEID.equals(node.getId())) {
			onRefresh();
			return;
		}
		OntologyServiceManager.getInstance().getSubproperties(
				getProject().getProjectId(), node.getId(),
				new AsyncCallback<List<EntityData>>() {

					@Override
					public void onFailure(Throwable caught) {
						GWT.log("getSubproperties Failure.", caught);
					}

					@Override
					public void onSuccess(final List<EntityData> result) {
						if (result == null) {
							return;
						}

						AsyncCallback<EntityData> callback = new AsyncCallback<EntityData>() {

							@Override
							public void onFailure(Throwable caught) {
								GWT.log("Failure", caught);
							}

							@Override
							public void onSuccess(EntityData result) {
								TreeNode treeNode = createTreeNode(result);
								if (treeNode != null) {
									node.appendChild(treeNode);
								}
							}

						};

						for (EntityData entityData : result) {
							getEntityChildrenCount(entityData, callback);
						}
					}
				});
	}
}
